package system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import common.config.datasource.DataSourceConstants;
import common.config.exception.CustomException;
import common.config.jwt.JwtUtil;
import common.config.jwt.TokenInfo;
import common.config.rocketmq.MqTaskEnum;
import common.mapper.CommonSysUserMapper;
import common.model.converter.CommonSysAuthorityConverter;
import common.model.dto.ActivateEmailToken;
import common.model.dto.LoginToken;
import common.model.dto.ModifyEmailToken;
import common.model.dto.ModifyPasswordToken;
import common.model.enums.*;
import common.model.po.*;
import common.model.po.base.BasePo;
import common.model.request.RegisterRequest;
import common.model.request.SendEmailRequest;
import common.model.request.base.PaginationRequest;
import common.model.response.base.Result;
import common.model.vo.ButtonVo;
import common.model.vo.MenuVo;
import common.service.*;
import common.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import system.config.rocketmq.producer.UpdateUsernameOrNicknameMqProducer;
import system.config.rocketmq.producer.UserDrawDownMqProducer;
import system.model.converter.SysUserConverter;
import system.model.request.*;
import system.model.response.UpdateMyselfResponse;
import system.model.response.UpdateUserResponse;
import system.service.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.time.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author 米泽鹏
 * @since 2022-03-22
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<CommonSysUserMapper, SysUser> implements SysUserService {

	@Resource
	private CommonSysUserMapper mapper;
	@Resource
	private CommonSysUserRoleService userRoleService;
	@Resource
	private MailService mailService;
	@Resource
	private CommonSysRoleAuthorityService commonRoleAuthorityService;
	@Resource
	private CommonSysWebConfigService webConfigService;
	@Resource
	private CommonSysAuthorityService commonAuthorityService;
	@Resource
	private SysRoleService roleService;
	@Resource
	private SysLogService logService;
	@Resource
	private SysTopicService topicService;
	@Resource
	private SysTopicCommentService commentService;
	@Resource
	private SysTopicLikeService topicLikeService;
	@Resource
	private SysTopicCommentLikeService commentLikeService;
	@Resource
	private CommonGUserProductionService userProductionService;
	@Resource
	private RedissonCacheService redissonCacheService;
	@Resource
	private UserDrawDownMqProducer userDrawDownMqProducer;
	@Resource
	private UpdateUsernameOrNicknameMqProducer updateUsernameOrNicknameMqProducer;
	@Value("${spring.application.name}")
	private String appName;
	@Value("${satisfactory.domain}")
	private String domain;

	@Override
	public Page<SysUser> pageUser(PaginationRequest<SearchUserRequest, SysUser> paginationRequest) {
		LambdaQueryWrapper<SysUser> queryWrapper = paginationRequest.buildQueryWrapper().lambda();
		Boolean hasEmail = paginationRequest.getParams().getHasEmail();
		if (hasEmail != null) {
			if (hasEmail) {
				queryWrapper.isNotNull(SysUser::getEmail).ne(SysUser::getEmail, "");
			} else {
				queryWrapper.and(wrapper -> wrapper.isNull(SysUser::getEmail).or().eq(SysUser::getEmail, ""));
			}
		}
		queryWrapper.select(SysUser.class, tableFieldInfo -> !ClassUtil.getFieldName(SysUser::getSalt).equals(tableFieldInfo.getProperty()) && !ClassUtil.getFieldName(SysUser::getPassword).equals(tableFieldInfo.getProperty()));
		queryWrapper.orderByDesc(SysUser::getId);
		return page(paginationRequest.buildPage(), queryWrapper);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<?> saveUser(SaveUserRequest request) {
		SysUser oneByUsername = lambdaQuery().eq(SysUser::getUsername, request.getUsername()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		SysUser oneByNickname = lambdaQuery().eq(SysUser::getNickname, request.getNickname()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		SysUser oneByEmail = lambdaQuery().eq(SysUser::getEmail, request.getEmail()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		// 新增
		Long userId = request.getId();
		if (userId == null) {
			if (SensitiveWordUtil.isSensitive(request.getUsername())) {
				throw new CustomException("非法用户名");
			}
			if (SensitiveWordUtil.isSensitive(request.getNickname())) {
				throw new CustomException("非法昵称");
			}
			if (oneByUsername != null) {
				throw new CustomException("用户名已被使用");
			}
			if (oneByNickname != null) {
				throw new CustomException("昵称已被使用");
			}
			if (oneByEmail != null) {
				throw new CustomException("此邮箱已被其他账号绑定");
			}
			String salt = GUID.randomGuid(Constants.PASSWORD_SALT_LENGTH);
			String encodedPassword = EncryptionUtil.encode(request.getPassword(), salt);
			request.setPassword(encodedPassword);
			SysUser po = SysUserConverter.saveRequestToPo(request);
			po.setSalt(salt);
			po.setEmailNotifyTypes(Arrays.stream(EmailNotifyTypeEnum.values()).map(EmailNotifyTypeEnum::getValue).collect(Collectors.toList()));
			// 用户
			po.insert();
			// 用户和角色的关联关系
			List<SysUserRole> userRoleList = Lists.newArrayList();
			for (SysRole role : request.getRoleList()) {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(po.getId());
				userRole.setRoleId(role.getId());
				userRoleList.add(userRole);
			}
			userRoleService.saveBatch(userRoleList);
			// 更新缓存
			redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
			redissonCacheService.cacheSysUserRole(userRoleService.getAllSysUserRole()).throwExceptionIfFailed();
			return Result.success();
		}
		// 更新
		else {
			SysUser userOriginal = getById(userId);
			String originalUsername = userOriginal.getUsername();
			String originalNickname = userOriginal.getNickname();
			String newUsername = request.getUsername();
			String newNickname = request.getNickname();
			boolean modifyUsernameFlag = !newUsername.equals(originalUsername);
			boolean modifyNicknameFlag = !newNickname.equals(originalNickname);
			if (modifyUsernameFlag) {
				if (SensitiveWordUtil.isSensitive(originalUsername)) {
					throw new CustomException("该用户无法修改用户名：" + originalUsername);
				}
				if (SensitiveWordUtil.isSensitive(newUsername)) {
					throw new CustomException("非法用户名");
				}
			}
			if (modifyNicknameFlag) {
				if (SensitiveWordUtil.isSensitive(originalNickname)) {
					throw new CustomException("该用户无法修改昵称：" + originalNickname);
				}
				if (SensitiveWordUtil.isSensitive(newNickname)) {
					throw new CustomException("非法昵称");
				}
			}
			// 是否需要修改密码
			String newPassword = null;
			Boolean changePasswordFlag = request.getChangePasswordFlag();
			if (changePasswordFlag) {
				if (StrUtil.isBlank(request.getPassword())) {
					throw new CustomException("密码不能为空");
				}
				newPassword = EncryptionUtil.encode(request.getPassword(), userOriginal.getSalt());
			}
			boolean modifyPasswordFlag = changePasswordFlag && !newPassword.equals(userOriginal.getPassword());
			if (oneByUsername != null && !userId.equals(oneByUsername.getId())) {
				throw new CustomException("用户名已被使用");
			}
			if (oneByNickname != null && !userId.equals(oneByNickname.getId())) {
				throw new CustomException("昵称已被使用");
			}
			if (oneByEmail != null && !userId.equals(oneByEmail.getId())) {
				throw new CustomException("此邮箱已被其他账号绑定");
			}
			// 最高管理员不能被禁用
			List<SysRole> roleList = roleService.getRolesByUserId(userId);
			if (roleList.stream().anyMatch(role -> SpecialRoleEnum.MASTER.getRoleCode().equals(role.getRoleCode()) && UserValidEnum.INVALID.getValue().equals(request.getValid()))) {
				throw new CustomException(SpecialRoleEnum.MASTER.getRoleName() + "不能被禁用");
			}
			// 不能禁用当前登录的账号
			LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
			if (loginToken.getUserId().equals(userId) && UserValidEnum.INVALID.getValue().equals(request.getValid())) {
				throw new CustomException("不能禁用当前登录的账号，请使用其他账号执行操作");
			}
			// 更新用户
			lambdaUpdate().eq(SysUser::getId, userId).set(modifyPasswordFlag, SysUser::getPassword, newPassword).set(SysUser::getUsername, newUsername).set(SysUser::getNickname, newNickname).set(SysUser::getValid, request.getValid()).set(SysUser::getEmail, request.getEmail()).set(SysUser::getEmailValid, request.getEmailValid()).set(SysUser::getEmailNotifyTypes, request.getEmailNotifyTypes(), "typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler").set(SysUser::getAvatar, request.getAvatar()).set(SysUser::getGender, request.getGender()).set(SysUser::getIntroduction, request.getIntroduction()).update();
			// 如果修改了密码，则删除loginToken的缓存，使用户下线
			if (modifyPasswordFlag) {
				redissonCacheService.removeLoginTokenStringByUserId(userId).throwExceptionIfFailed();
			}
			// 更新所有表的用户名和昵称
			UpdateUsernameOrNicknameRequest updateUsernameOrNicknameRequest = new UpdateUsernameOrNicknameRequest();
			updateUsernameOrNicknameRequest.setUserId(userId);
			updateUsernameOrNicknameRequest.setUsername(newUsername);
			updateUsernameOrNicknameRequest.setNickname(newNickname);
			updateUsernameOrNickname(updateUsernameOrNicknameRequest, userOriginal, false, false, true);
			// 用户和角色的关联关系
			List<Long> currentRoleIdList = userRoleService.lambdaQuery().eq(SysUserRole::getUserId, userId).list().stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
			List<Long> destinationRoleIdList = request.getRoleList().stream().map(SysRole::getId).collect(Collectors.toList());
			List<Long> deleteRoleIdList = CompareUtil.getDeleteIdList(currentRoleIdList, destinationRoleIdList);
			List<Long> insertRoleIdList = CompareUtil.getInsertIdList(currentRoleIdList, destinationRoleIdList);
			if (!deleteRoleIdList.isEmpty()) {
				userRoleService.lambdaUpdate().eq(SysUserRole::getUserId, userId).in(SysUserRole::getRoleId, deleteRoleIdList).remove();
			}
			List<SysUserRole> userRoleList = Lists.newArrayList();
			for (Long roleId : insertRoleIdList) {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(userId);
				userRole.setRoleId(roleId);
				userRoleList.add(userRole);
			}
			userRoleService.saveBatch(userRoleList);
			boolean modifyValidFlag = !request.getValid().equals(userOriginal.getValid());
			boolean modifyUserRoleFlag = !deleteRoleIdList.isEmpty() || !insertRoleIdList.isEmpty();
			// 更新缓存
			if (modifyUsernameFlag || modifyNicknameFlag || modifyValidFlag) {
				redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
			}
			if (!deleteRoleIdList.isEmpty() || !insertRoleIdList.isEmpty()) {
				redissonCacheService.cacheSysUserRole(userRoleService.getAllSysUserRole()).throwExceptionIfFailed();
			}
			UpdateUserResponse updateUserResponse = null;
			// 修改的是自己的信息
			if (loginToken.getUserId().equals(userId)) {
				updateUserResponse = new UpdateUserResponse();
				updateUserResponse.setUser(getById(userId));
				// 如果修改了用户名、昵称、角色中的任意一个，则生成并返回新token
				if (modifyUsernameFlag || modifyNicknameFlag || modifyUserRoleFlag) {
					// 查询该用户具有的权限
					List<SysUserRole> newUserRoleList = userRoleService.lambdaQuery().eq(SysUserRole::getUserId, userId).list();
					List<SysRoleAuthority> roleAuthorityList = commonRoleAuthorityService.lambdaQuery().in(SysRoleAuthority::getRoleId, newUserRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet())).list();
					List<Long> authorityIdList = roleAuthorityList.stream().map(SysRoleAuthority::getAuthId).distinct().collect(Collectors.toList());
					LoginToken newLoginToken = new LoginToken(userId, newUsername, newNickname, new HashSet<>(destinationRoleIdList), new HashSet<>(authorityIdList));
					TokenInfo tokenInfo = JwtUtil.createLoginToken(newLoginToken);
					updateUserResponse.setToken(tokenInfo.getToken());
					updateUserResponse.setExpire(tokenInfo.getExpireDate());
					// 更新token缓存
					redissonCacheService.cacheLoginTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate());
					// 如果修改了用户的角色，则返回新的菜单和按钮权限，以及是否是管理员
					if (modifyUserRoleFlag) {
						if (CollectionUtil.isNotEmpty(authorityIdList)) {
							Set<ButtonVo> buttons = Sets.newHashSet();
							List<SysAuthority> authorityList = commonAuthorityService.listByIds(authorityIdList);
							List<SysAuthority> authorityMenuList = Lists.newArrayList();
							authorityList.forEach(authority -> {
								if (SysAuthorityTypeEnum.MENU.getValue().equals(authority.getType()) || SysAuthorityTypeEnum.STRUCTURE.getValue().equals(authority.getType())) {
									authorityMenuList.add(authority);
								}
								if (SysAuthorityTypeEnum.BUTTON.getValue().equals(authority.getType())) {
									ButtonVo buttonVO = CommonSysAuthorityConverter.poToButtonVO(authority);
									buttons.add(buttonVO);
								}
							});
							Set<MenuVo> menus = RouteUtil.buildRoutes(authorityMenuList);
							updateUserResponse.setMenus(menus);
							updateUserResponse.setButtons(buttons);
						} else {
							updateUserResponse.setMenus(Collections.emptySet());
							updateUserResponse.setButtons(Collections.emptySet());
						}
						List<SysRole> newRoleList = roleService.listByIds(newUserRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet()));
						updateUserResponse.setIsAdmin(newRoleList.stream().anyMatch(role -> RoleIsAdminEnum.IS_ADMIN.getValue().equals(role.getIsAdmin())));
					}
				}
			}
			return Result.successWithData(updateUserResponse);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<?> deleteUser(Long userId) {
		// 最高管理员不能被删除
		List<SysRole> roleList = roleService.getRolesByUserId(userId);
		if (roleList.stream().anyMatch(role -> SpecialRoleEnum.MASTER.getRoleCode().equals(role.getRoleCode()))) {
			throw new CustomException(SpecialRoleEnum.MASTER.getRoleName() + "不能被删除");
		}
		// 不能删除当前登录的账号
		LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
		if (loginToken.getUserId().equals(userId)) {
			throw new CustomException("不能删除当前登录的账号，请使用其他账号执行操作");
		}
		SysUser user = getById(userId);
		// 设置用户状态为不可用
		lambdaUpdate().eq(SysUser::getId, userId).set(SysUser::getValid, UserValidEnum.INVALID.getValue()).update();
		// 删除用户
		deleteUserInner(user).throwExceptionIfFailed();
		return Result.success();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<?> register(RegisterRequest request) {
		if (SensitiveWordUtil.isSensitive(request.getUsername())) {
			throw new CustomException("非法用户名");
		}
		if (SensitiveWordUtil.isSensitive(request.getNickname())) {
			throw new CustomException("非法昵称");
		}
		SysUser oneByUsername = lambdaQuery().eq(SysUser::getUsername, request.getUsername()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		if (oneByUsername != null) {
			throw new CustomException("用户名已被使用");
		}
		SysUser oneByNickname = lambdaQuery().eq(SysUser::getNickname, request.getNickname()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		if (oneByNickname != null) {
			throw new CustomException("昵称已被使用");
		}
		String email = request.getEmail();
		if (StrUtil.isNotBlank(email)) {
			SysUser oneByEmail = lambdaQuery().eq(SysUser::getEmail, email).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
			if (oneByEmail != null) {
				throw new CustomException("此邮箱已被其他账号绑定");
			}
		}
		String salt = GUID.randomGuid(Constants.PASSWORD_SALT_LENGTH);
		String encodedPassword = EncryptionUtil.encode(request.getPassword(), salt);
		SysUser po = SysUserConverter.registerRequestToPo(request);
		po.setPassword(encodedPassword);
		po.setSalt(salt);
		po.setEmailValid(EmailValidEnum.INVALID.getValue());
		po.setEmailNotifyTypes(Arrays.stream(EmailNotifyTypeEnum.values()).map(EmailNotifyTypeEnum::getValue).collect(Collectors.toList()));
		po.setValid(UserValidEnum.VALID.getValue());
		po.setOperator(request.getUsername());
		po.insert();
		Long userId = po.getId();
		// 用户和角色的关联关系，注册的用户都默认是外部用户角色
		SysRole externalUserRole = roleService.lambdaQuery().eq(SysRole::getRoleCode, SpecialRoleEnum.EXTERNAL_USER.getRoleCode()).one();
		if (externalUserRole == null) {
			throw new CustomException("系统未配置外部用户角色，请联系管理员");
		}
		SysUserRole userRole = new SysUserRole();
		userRole.setUserId(userId);
		userRole.setRoleId(externalUserRole.getId());
		userRole.setOperator(request.getUsername());
		userRole.insert();
		// 更新缓存
		redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
		redissonCacheService.cacheSysUserRole(userRoleService.getAllSysUserRole()).throwExceptionIfFailed();
		// 邮件通知
		if (StrUtil.isNotBlank(email)) {
			// 生成邮箱激活的token
			ActivateEmailToken activateEmailToken = new ActivateEmailToken();
			activateEmailToken.setUserId(userId);
			activateEmailToken.setNewEmail(request.getEmail());
			TokenInfo tokenInfo = JwtUtil.createActivateEmailToken(activateEmailToken);
			redissonCacheService.cacheActivateEmailTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate()).throwExceptionIfFailed();
			// 发送邮箱激活邮件
			SendEmailRequest sendEmailRequest = new SendEmailRequest();
			sendEmailRequest.setToList(Collections.singletonList(email));
			sendEmailRequest.setSubject("激活邮箱【幸福工厂游戏工具网站】");
			sendEmailRequest.setText(EmailTemplateUtil.getActivateMailBoxContent(domain, tokenInfo.getToken(), po.getUsername(), po.getNickname()));
			sendEmailRequest.setHtml(true);
			mailService.sendEmail(sendEmailRequest);
		}
		return Result.success();
	}

	/**
	 * 消息延迟等级<br/>
	 * {@link org.apache.rocketmq.remoting.protocol.subscription.CustomizedRetryPolicy}
	 */
	@Override
	public Result<?> sendDrawDownMq(Long userId) {
		// 管理员不能自行注销，只能在用户管理中删除
		List<SysRole> roleList = roleService.getRolesByUserId(userId);
		if (roleList.stream().anyMatch(role -> RoleIsAdminEnum.IS_ADMIN.getValue().equals(role.getIsAdmin()))) {
			throw new CustomException("管理员不能自行注销，请在用户管理中删除");
		}
		Message message;
		try {
			message = new Message(MqTaskEnum.USER_DRAW_DOWN.getTopic(), appName, String.valueOf(userId).getBytes(RemotingHelper.DEFAULT_CHARSET));
		} catch (UnsupportedEncodingException e) {
			log.error(ExceptionUtil.getRootCauseMessage(e));
			throw new CustomException("RocketMQ消息创建时出现异常：" + ExceptionUtil.getSimpleMessage(e));
		}
		// 设置延时等级18，这个消息将在2h之后发送（现在只支持固定的几个时间，详看delayTimeLevel）
		// org.apache.rocketmq.store.config.MessageStoreConfig.java
		// private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
		// org.apache.rocketmq.remoting.protocol.subscription.CustomizedRetryPolicy.java
		// 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
		message.setDelayTimeLevel(18);
		// 发送消息
		try {
			userDrawDownMqProducer.send(message);
		} catch (Throwable t) {
			log.error(t.getMessage());
			throw new CustomException("RocketMQ延时消息发送时出现异常：" + ExceptionUtil.getSimpleMessage(t));
		}
		log.info("已发送RocketMQ延时消息：{}，用户id：" + userId + "，延迟时间：2小时，来自服务：{}", MqTaskEnum.USER_DRAW_DOWN.getDescription(), appName);
		// 设置用户状态为不可用、设置用户删除状态为预备删除
		lambdaUpdate().eq(SysUser::getId, userId).set(SysUser::getValid, UserValidEnum.INVALID.getValue()).set(SysUser::getIsDeleted, UserDeletedEnum.PRE_DELETED.getValue()).update();
		// 邮件通知
		SysUser user = getById(userId);
		String email = user.getEmail();
		if (EmailNotifyTypeEnum.check(EmailNotifyTypeEnum.ACCOUNT_DELETION, user)) {
			SendEmailRequest sendEmailRequest = new SendEmailRequest();
			sendEmailRequest.setToList(Collections.singletonList(email));
			sendEmailRequest.setSubject(EmailNotifyTypeEnum.ACCOUNT_DELETION.getDesc() + "【幸福工厂游戏工具网站】");
			sendEmailRequest.setText(EmailTemplateUtil.getAccountDeletionContent(domain, user.getUsername(), user.getNickname()));
			sendEmailRequest.setHtml(true);
			mailService.sendEmail(sendEmailRequest);
		}
		return Result.success();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<SysUser> drawDown(Long userId) {
		SysUser user = getById(userId);
		if (user == null) {
			String message = "用户不存在，取消删除，userId：" + userId;
			log.info(message);
			return Result.error(message);
		}
		if (!UserDeletedEnum.PRE_DELETED.getValue().equals(user.getIsDeleted())) {
			// 恢复账号为正常状态
			user.setValid(UserValidEnum.VALID.getValue());
			user.setIsDeleted(UserDeletedEnum.NOT_DELETED.getValue());
			user.updateById();
			String message = "用户状态不为" + UserDeletedEnum.PRE_DELETED.getDesc() + "，取消删除：" + JSONUtil.toJsonStr(user);
			log.info(message);
			return Result.error(message);
		}
		if (!UserValidEnum.INVALID.getValue().equals(user.getValid())) {
			// 恢复账号为正常状态
			user.setValid(UserValidEnum.VALID.getValue());
			user.setIsDeleted(UserDeletedEnum.NOT_DELETED.getValue());
			user.updateById();
			String message = "用户状态不为" + UserValidEnum.INVALID.getDesc() + "，取消删除：" + JSONUtil.toJsonStr(user);
			log.info(message);
			return Result.error(message);
		}
		// 删除用户
		deleteUserInner(user).throwExceptionIfFailed();
		return Result.successWithData(user);
	}

	@Transactional(rollbackFor = Exception.class)
	public Result<?> deleteUserInner(SysUser user) {
		// 将用户改为已删除状态，记录删除前的用户名和昵称
		lambdaUpdate().eq(SysUser::getId, user.getId()).set(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).set(SysUser::getOriginalUsername, user.getUsername()).set(SysUser::getOriginalNickname, user.getNickname()).update();
		// 更新所有表的用户名和昵称
		UpdateUsernameOrNicknameRequest updateUsernameOrNicknameRequest = new UpdateUsernameOrNicknameRequest();
		updateUsernameOrNicknameRequest.setUserId(user.getId());
		updateUsernameOrNicknameRequest.setUsername(Constants.DELETED_USERNAME_PREFIX + "_" + user.getId());
		updateUsernameOrNicknameRequest.setNickname(Constants.DELETED_NICKNAME_PREFIX + "_" + user.getId());
		updateUsernameOrNickname(updateUsernameOrNicknameRequest, user, true, false, false);
		// 更新缓存
		redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
		redissonCacheService.cacheSysUserRole(userRoleService.getAllSysUserRole()).throwExceptionIfFailed();
		return Result.success();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<UpdateMyselfResponse> updateMyself(UpdateMyselfRequest request) {
		Long userId = request.getUserId();
		String newEmail = request.getEmail();
		String newUsername = request.getUsername();
		String newNickname = request.getNickname();

		// 修改前的用户信息
		SysUser userOriginal = getById(userId);
		String originalUsername = userOriginal.getUsername();
		String originalNickname = userOriginal.getNickname();
		String originalEmail = userOriginal.getEmail();

		boolean modifyUsernameFlag = !Objects.equals(originalUsername, newUsername);
		boolean modifyNicknameFlag = !Objects.equals(originalNickname, newNickname);
		if (modifyUsernameFlag) {
			if (SensitiveWordUtil.isSensitive(originalUsername)) {
				throw new CustomException("该用户无法修改用户名：" + originalUsername);
			}
			if (SensitiveWordUtil.isSensitive(newUsername)) {
				throw new CustomException("非法用户名");
			}
		}
		if (modifyNicknameFlag) {
			if (SensitiveWordUtil.isSensitive(originalNickname)) {
				throw new CustomException("该用户无法修改昵称：" + originalNickname);
			}
			if (SensitiveWordUtil.isSensitive(newNickname)) {
				throw new CustomException("非法昵称");
			}
		}
		SysUser oneByUsername = lambdaQuery().eq(SysUser::getUsername, newUsername).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		if (oneByUsername != null && !userId.equals(oneByUsername.getId())) {
			throw new CustomException("用户名已被使用");
		}
		SysUser oneByNickname = lambdaQuery().eq(SysUser::getNickname, newNickname).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
		if (oneByNickname != null && !userId.equals(oneByNickname.getId())) {
			throw new CustomException("昵称已被使用");
		}
		// 更新用户表信息
		Date now = new Date();

		boolean modifyEmailFlag = !Objects.equals(originalEmail, newEmail);
		// 校验邮箱是否被其他账号绑定
		if (modifyEmailFlag && StrUtil.isNotBlank(newEmail)) {
			SysUser oneByEmail = lambdaQuery().eq(SysUser::getEmail, newEmail).ne(SysUser::getId, userId).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
			if (oneByEmail != null) {
				throw new CustomException("此邮箱已被其他账号绑定");
			}
		}
		// 更新个人信息
		lambdaUpdate().eq(SysUser::getId, userId).set(SysUser::getUsername, newUsername).set(SysUser::getNickname, newNickname).set(SysUser::getEmail, newEmail).set(modifyEmailFlag, SysUser::getEmailValid, EmailValidEnum.INVALID.getValue()).set(SysUser::getGender, request.getGender()).set(SysUser::getAvatar, request.getAvatar()).set(SysUser::getIntroduction, request.getIntroduction()).set(modifyUsernameFlag, SysUser::getLastModifyUsernameDate, now).set(modifyNicknameFlag, SysUser::getLastModifyNicknameDate, now).update();
		// 更新所有表的用户名和昵称
		UpdateUsernameOrNicknameRequest updateUsernameOrNicknameRequest = new UpdateUsernameOrNicknameRequest();
		updateUsernameOrNicknameRequest.setUserId(userId);
		updateUsernameOrNicknameRequest.setUsername(newUsername);
		updateUsernameOrNicknameRequest.setNickname(newNickname);
		updateUsernameOrNickname(updateUsernameOrNicknameRequest, userOriginal, false, true, true);
		// 更新缓存
		if (!newUsername.equals(originalUsername) || !newNickname.equals(originalNickname)) {
			redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
		}
		// 响应数据
		UpdateMyselfResponse updateMyselfResponse = new UpdateMyselfResponse();
		SysUser newUser = getById(userId);
		updateMyselfResponse.setUser(newUser);
		// 如果修改了用户名或昵称，则生成并返回新的token
		if (modifyUsernameFlag || modifyNicknameFlag) {
			LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
			LoginToken newLoginToken = new LoginToken(newUser.getId(), newUser.getUsername(), newUser.getNickname(), loginToken.getRoleIdSet(), loginToken.getAuthorityIdSet());
			TokenInfo tokenInfo = JwtUtil.createLoginToken(newLoginToken);
			updateMyselfResponse.setToken(tokenInfo.getToken());
			updateMyselfResponse.setExpire(tokenInfo.getExpireDate());
			// 更新token缓存
			redissonCacheService.cacheLoginTokenString(newUser.getId(), tokenInfo.getToken(), tokenInfo.getExpireDate());
		}
		// 如果老邮箱已激活，则发送用户信息变更通知
		Integer oldEmailValid = userOriginal.getEmailValid();
		if (EmailNotifyTypeEnum.check(EmailNotifyTypeEnum.IMPORTANT_USER_INFO_MODIFIED, originalEmail, oldEmailValid, newUser.getEmailNotifyTypes()) && (modifyUsernameFlag || modifyNicknameFlag)) {
			SendEmailRequest sendEmailRequest = new SendEmailRequest();
			sendEmailRequest.setToList(Collections.singletonList(newEmail));
			sendEmailRequest.setSubject("个人信息变更【幸福工厂游戏工具网站】");
			// 用户名和密码用于登录，是敏感信息，二者被修改后，需要提示用户账号可能有风险，并生成修改密码的临时链接，有效期30分钟
			ModifyPasswordToken modifyPasswordToken = new ModifyPasswordToken();
			modifyPasswordToken.setUserId(userId);
			TokenInfo tokenInfo = JwtUtil.createModifyPasswordToken(modifyPasswordToken);
			redissonCacheService.cacheModifyPasswordTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate()).throwExceptionIfFailed();
			sendEmailRequest.setText(EmailTemplateUtil.getModifyUserInfoContent(domain, tokenInfo.getToken(), modifyUsernameFlag ? newUser.getUsername() : null, modifyNicknameFlag ? newUser.getNickname() : null));
			sendEmailRequest.setHtml(true);
			mailService.sendEmail(sendEmailRequest);
		}
		// 关于邮箱的变更分三种情况：
		// ① 首次绑定邮箱：设置了新邮箱，且没有旧邮箱或旧邮箱未激活，则向新邮箱发送激活链接
		// ② 邮箱换绑：设置了新邮箱，且新邮箱与旧邮箱不同，且旧邮箱存在，且旧邮箱已激活，则向旧邮箱发送邮箱换绑链接
		// ③ 邮箱解绑：没有填写新邮箱，且旧邮箱存在，且旧邮箱已激活，且订阅了旧邮箱解绑通知，则向旧邮箱发送解绑通知
		if (StrUtil.isNotBlank(newEmail)) {
			// ① 首次绑定邮箱：设置了新邮箱（已为true），且没有旧邮箱或旧邮箱未激活，则向新邮箱发送激活链接
			if (StrUtil.isBlank(originalEmail) || EmailValidEnum.INVALID.getValue().equals(oldEmailValid)) {
				// 生成邮箱激活的token
				ActivateEmailToken activateEmailToken = new ActivateEmailToken();
				activateEmailToken.setUserId(userId);
				activateEmailToken.setNewEmail(request.getEmail());
				TokenInfo tokenInfo = JwtUtil.createActivateEmailToken(activateEmailToken);
				redissonCacheService.cacheActivateEmailTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate()).throwExceptionIfFailed();
				SendEmailRequest sendEmailRequest = new SendEmailRequest();
				sendEmailRequest.setToList(Collections.singletonList(newEmail));
				sendEmailRequest.setSubject("激活邮箱【幸福工厂游戏工具网站】");
				sendEmailRequest.setText(EmailTemplateUtil.getActivateMailBoxContent(domain, tokenInfo.getToken(), newUser.getUsername(), newUser.getNickname()));
				sendEmailRequest.setHtml(true);
				mailService.sendEmail(sendEmailRequest);
			}
			// ② 邮箱换绑：设置了新邮箱（已为true），且新邮箱与旧邮箱不同，且旧邮箱存在（已为true），且旧邮箱已激活（已为true），则向旧邮箱发送邮箱换绑链接
			else if (modifyEmailFlag) {
				ModifyEmailToken modifyEmailToken = new ModifyEmailToken();
				modifyEmailToken.setUserId(userId);
				modifyEmailToken.setNewEmail(newEmail);
				modifyEmailToken.setOldEmail(originalEmail);
				TokenInfo tokenInfo = JwtUtil.createModifyEmailToken(modifyEmailToken);
				redissonCacheService.cacheModifyEmailTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate()).throwExceptionIfFailed();
				SendEmailRequest sendEmailRequest = new SendEmailRequest();
				sendEmailRequest.setToList(Collections.singletonList(originalEmail));
				sendEmailRequest.setSubject("邮箱换绑【幸福工厂游戏工具网站】");
				sendEmailRequest.setText(EmailTemplateUtil.getModifyEmailContent(domain, tokenInfo.getToken(), originalEmail, newEmail, newUser.getUsername(), newUser.getNickname()));
				sendEmailRequest.setHtml(true);
				mailService.sendEmail(sendEmailRequest);
				// 发送2h延时消息，携带 ModifyEmailToken 的信息，到期后，如果用户存在且未删除，且用户此时的邮箱与token中的新邮箱相同，且用户邮箱处于未激活状态，则将邮箱恢复至旧邮箱，且状态设置为已激活
				Message message;
				try {
					message = new Message(MqTaskEnum.MODIFY_EMAIL.getTopic(), appName, JSONUtil.toJsonStr(modifyEmailToken).getBytes(RemotingHelper.DEFAULT_CHARSET));
				} catch (UnsupportedEncodingException e) {
					log.error(ExceptionUtil.getRootCauseMessage(e));
					throw new CustomException("RocketMQ消息创建时出现异常：" + ExceptionUtil.getSimpleMessage(e));
				}
				// 设置延时等级18，这个消息将在2h之后发送（现在只支持固定的几个时间，详看delayTimeLevel）
				// org.apache.rocketmq.store.config.MessageStoreConfig.java
				// private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
				// org.apache.rocketmq.remoting.protocol.subscription.CustomizedRetryPolicy.java
				// 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
				message.setDelayTimeLevel(18);
				// 发送消息
				try {
					userDrawDownMqProducer.send(message);
				} catch (Throwable t) {
					log.error(t.getMessage());
					throw new CustomException("RocketMQ延时消息发送时出现异常：" + ExceptionUtil.getSimpleMessage(t));
				}
				log.info("已发送RocketMQ延时消息：{}，用户id：" + userId + "，延迟时间：2小时，来自服务：{}", MqTaskEnum.MODIFY_EMAIL.getDescription(), appName);
			}
		}
		// ③ 邮箱解绑：没有填写新邮箱（已为true），且旧邮箱存在，且旧邮箱已激活，且订阅了旧邮箱解绑通知，则向旧邮箱发送解绑通知
		else if (EmailNotifyTypeEnum.check(EmailNotifyTypeEnum.EMAIL_UNBOUND, originalEmail, oldEmailValid, newUser.getEmailNotifyTypes())) {
			SendEmailRequest sendEmailRequest = new SendEmailRequest();
			sendEmailRequest.setToList(Collections.singletonList(originalEmail));
			sendEmailRequest.setSubject(EmailNotifyTypeEnum.EMAIL_UNBOUND.getDesc() + "【幸福工厂游戏工具网站】");
			sendEmailRequest.setText(EmailTemplateUtil.getEmailUnboundContent(domain, newUser.getUsername(), newUser.getNickname()));
			sendEmailRequest.setHtml(true);
			mailService.sendEmail(sendEmailRequest);
		}
		return Result.successWithData(updateMyselfResponse);
	}

	@Override
	public Result<?> updateMyPassword(UpdateMyPasswordRequest request) {
		Long userId = request.getUserId();
		SysUser user = getById(userId);
		if (!EncryptionUtil.encode(request.getOldPassword(), user.getSalt()).equals(user.getPassword())) {
			throw new CustomException("旧密码错误");
		}
		if (request.getNewPassword().equals(request.getOldPassword())) {
			throw new CustomException("新密码不能与旧密码相同");
		}
		user.setPassword(EncryptionUtil.encode(request.getNewPassword(), user.getSalt()));
		user.updateById();
		// 邮件通知
		String email = user.getEmail();
		if (EmailNotifyTypeEnum.check(EmailNotifyTypeEnum.IMPORTANT_USER_INFO_MODIFIED, user)) {
			SendEmailRequest sendEmailRequest = new SendEmailRequest();
			sendEmailRequest.setToList(Collections.singletonList(email));
			sendEmailRequest.setSubject("密码变更【幸福工厂游戏工具网站】");
			// 用户名和密码用于登录，是敏感信息，二者被修改后，需要提示用户账号可能有风险，并生成修改密码的临时链接，有效期30分钟
			ModifyPasswordToken modifyPasswordToken = new ModifyPasswordToken();
			modifyPasswordToken.setUserId(userId);
			TokenInfo tokenInfo = JwtUtil.createModifyPasswordToken(modifyPasswordToken);
			redissonCacheService.cacheModifyPasswordTokenString(userId, tokenInfo.getToken(), tokenInfo.getExpireDate()).throwExceptionIfFailed();
			sendEmailRequest.setText(EmailTemplateUtil.getModifyPasswordContent(domain, tokenInfo.getToken(), user.getUsername(), user.getNickname()));
			sendEmailRequest.setHtml(true);
			mailService.sendEmail(sendEmailRequest);
		}
		return Result.success();
	}

	@Override
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<Boolean> updateUserValid(UpdateUserValidRequest request) {
		// 不能禁用当前登录的账号
		LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
		if (loginToken.getUserId().equals(request.getId()) && UserValidEnum.INVALID.getValue().equals(request.getValid())) {
			throw new CustomException("不能禁用当前登录的账号，请使用其他账号执行操作");
		}
		// 最高管理员不能被禁用
		List<SysRole> roleList = roleService.getRolesByUserId(request.getId());
		if (roleList.stream().anyMatch(role -> SpecialRoleEnum.MASTER.getRoleCode().equals(role.getRoleCode()) && UserValidEnum.INVALID.getValue().equals(request.getValid()))) {
			throw new CustomException(SpecialRoleEnum.MASTER.getRoleName() + "不能被禁用");
		}
		boolean updated = lambdaUpdate().eq(SysUser::getId, request.getId()).set(SysUser::getValid, request.getValid()).update();
		if (updated) {
			// 更新缓存
			redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
		}
		return Result.successWithData(updated);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<Boolean> updateUsernameOrNickname(@Nonnull UpdateUsernameOrNicknameRequest request) {
		return updateUsernameOrNickname(request, null, true, true, true);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<Boolean> updateUsernameOrNickname(@Nonnull UpdateUsernameOrNicknameRequest request, @Nullable SysUser originalUser, boolean updateUserFlag, boolean checkModifyIntervalFlag, boolean checkSensitiveWordFlag) {
		Objects.requireNonNull(request, "更新请求参数request不能为空");
		if (request.getUserId() == null) {
			throw new CustomException("用户id不能为空");
		}
		if (StrUtil.isAllBlank(request.getUsername(), request.getNickname())) {
			throw new CustomException("用户名和昵称不能同时为空");
		}
		if (originalUser == null) {
			originalUser = getById(request.getUserId());
		} else {
			if (StrUtil.hasBlank(originalUser.getUsername(), originalUser.getNickname())) {
				throw new CustomException("修改前的用户信息不完整，用户名和昵称均不能为空");
			}
		}
		if (originalUser == null) {
			throw new CustomException("用户不存在");
		}
		boolean modifyUsernameFlag = StrUtil.isNotBlank(request.getUsername()) && !Objects.equals(request.getUsername(), originalUser.getUsername());
		boolean modifyNicknameFlag = StrUtil.isNotBlank(request.getNickname()) && !Objects.equals(request.getNickname(), originalUser.getNickname());
		if (modifyUsernameFlag || modifyNicknameFlag) {
			// 敏感词校验
			if (checkSensitiveWordFlag) {
				if (SensitiveWordUtil.isSensitive(originalUser.getUsername()) || SensitiveWordUtil.isSensitive(originalUser.getNickname())) {
					if (modifyUsernameFlag) {
						throw new CustomException("该用户无法修改用户名：" + originalUser.getUsername());
					}
					throw new CustomException("该用户无法修改昵称：" + originalUser.getNickname());
				} else {
					if (modifyUsernameFlag && SensitiveWordUtil.isSensitive(request.getUsername())) {
						throw new CustomException("非法用户名");
					}
					if (modifyNicknameFlag && SensitiveWordUtil.isSensitive(request.getNickname())) {
						throw new CustomException("非法昵称");
					}
				}
			}
			// 重复校验
			SysUser oneByUsername = lambdaQuery().eq(SysUser::getUsername, request.getUsername()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
			if (oneByUsername != null && !request.getUserId().equals(oneByUsername.getId())) {
				throw new CustomException("用户名已被使用");
			}
			SysUser oneByNickname = lambdaQuery().eq(SysUser::getNickname, request.getNickname()).ne(SysUser::getIsDeleted, UserDeletedEnum.DELETED.getValue()).one();
			if (oneByNickname != null && !request.getUserId().equals(oneByNickname.getId())) {
				throw new CustomException("昵称已被使用");
			}
			// 校验上次修改时间
			Date now = new Date();
			if (checkModifyIntervalFlag) {
				Date lastModifyUsernameDate = originalUser.getLastModifyUsernameDate();
				Date lastModifyNicknameDate = originalUser.getLastModifyNicknameDate();
				if (modifyUsernameFlag && lastModifyUsernameDate != null && DateUtil.between(lastModifyUsernameDate, now, DateUnit.SECOND) <= TimeUnit.DAYS.toSeconds(Constants.MODIFY_USERNAME_INTERVAL_DAY)) {
					ZonedDateTime zonedDateTime = lastModifyUsernameDate.toInstant().atZone(ZoneId.systemDefault());
					LocalDate localDate = zonedDateTime.toLocalDate();
					LocalTime localTime = zonedDateTime.toLocalTime();
					// 可以开始改名的时刻
					LocalDateTime localDateTime = LocalDateTime.of(localDate.plusDays(Constants.MODIFY_USERNAME_INTERVAL_DAY), localTime);
					Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
					throw new CustomException("用户名" + Constants.MODIFY_USERNAME_INTERVAL_DAY + "天内只能修改一次，您上次修改时间为" + DateUtil.formatDateTime(lastModifyUsernameDate) + "，请在" + DateUtil.formatDateTime(date) + "后修改");
				}
				if (modifyNicknameFlag && lastModifyNicknameDate != null && DateUtil.between(lastModifyNicknameDate, now, DateUnit.SECOND) <= TimeUnit.DAYS.toSeconds(Constants.MODIFY_NICKNAME_INTERVAL_DAY)) {
					ZonedDateTime zonedDateTime = lastModifyNicknameDate.toInstant().atZone(ZoneId.systemDefault());
					LocalDate localDate = zonedDateTime.toLocalDate();
					LocalTime localTime = zonedDateTime.toLocalTime();
					// 可以开始改名的时刻
					LocalDateTime localDateTime = LocalDateTime.of(localDate.plusDays(Constants.MODIFY_NICKNAME_INTERVAL_DAY), localTime);
					Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
					throw new CustomException("昵称" + Constants.MODIFY_NICKNAME_INTERVAL_DAY + "天内只能修改一次，您上次修改时间为" + DateUtil.formatDateTime(lastModifyNicknameDate) + "，请在" + DateUtil.formatDateTime(date) + "后修改");
				}
			}
			// 更新用户表的用户名和昵称
			if (updateUserFlag) {
				lambdaUpdate().eq(SysUser::getId, request.getUserId()).set(modifyUsernameFlag, SysUser::getUsername, request.getUsername()).set(modifyUsernameFlag && checkModifyIntervalFlag, SysUser::getLastModifyUsernameDate, now).set(modifyNicknameFlag, SysUser::getNickname, request.getNickname()).set(modifyNicknameFlag && checkModifyIntervalFlag, SysUser::getLastModifyNicknameDate, now).update();
			}
			// 更新sys_topic表的nickname
			// 更新sys_topic_comment表的nickname和reply_to_nickname
			if (modifyNicknameFlag) {
				topicService.lambdaUpdate().eq(SysTopic::getUserId, request.getUserId()).set(SysTopic::getNickname, request.getNickname()).update();
				commentService.lambdaUpdate().eq(SysTopicComment::getUserId, request.getUserId()).set(SysTopicComment::getNickname, request.getNickname()).update();
				commentService.lambdaUpdate().eq(SysTopicComment::getReplyToUserId, request.getUserId()).set(SysTopicComment::getReplyToNickname, request.getNickname()).update();
			}
			// 更新各个表的operator字段（MQ异步）
			if (modifyUsernameFlag) {
				Message message;
				try {
					UpdateOperatorRequest updateOperatorRequest = new UpdateOperatorRequest();
					updateOperatorRequest.setOldOperator(originalUser.getUsername());
					updateOperatorRequest.setNewOperator(request.getUsername());
					message = new Message(MqTaskEnum.UPDATE_USERNAME_OR_NICKNAME.getTopic(), appName, JSONUtil.toJsonStr(updateOperatorRequest).getBytes(RemotingHelper.DEFAULT_CHARSET));
				} catch (UnsupportedEncodingException e) {
					log.error(ExceptionUtil.getRootCauseMessage(e));
					throw new CustomException("RocketMQ消息创建时出现异常：" + ExceptionUtil.getSimpleMessage(e));
				}
				// 发送消息
				try {
					updateUsernameOrNicknameMqProducer.send(message);
				} catch (Throwable t) {
					log.error(t.getMessage());
					throw new CustomException("RocketMQ消息发送时出现异常：" + ExceptionUtil.getSimpleMessage(t));
				}
				log.info("已发送RocketMQ消息：{}，用户id：{}，来自服务：{}", MqTaskEnum.UPDATE_USERNAME_OR_NICKNAME.getDescription(), request.getUserId(), appName);
			}
		}
		return Result.successWithData(modifyUsernameFlag || modifyNicknameFlag);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<Boolean> clearUserData(Long userId) {
		// 不能清空当前登录账号的数据
		LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
		if (loginToken.getUserId().equals(userId)) {
			throw new CustomException("不能清空当前登录账号的数据，请使用其他账号执行操作");
		}
		// 最高管理员不能被删除
		List<SysRole> roleList = roleService.getRolesByUserId(userId);
		if (roleList.stream().anyMatch(role -> SpecialRoleEnum.MASTER.getRoleCode().equals(role.getRoleCode()))) {
			throw new CustomException(SpecialRoleEnum.MASTER.getRoleName() + "不能被删除");
		}
		SysUser user = getById(userId);
		if (user == null) {
			throw new CustomException("用户不存在");
		}
		return clearUserData(user);
	}

	@Override
	@DS(DataSourceConstants.MASTER_DATASOURCE)
	public Result<Boolean> clearUserData(SysUser user) {
		Long userId = user.getId();
		// 不能清空当前登录账号的数据
		LoginToken loginToken = JwtUtil.parseLoginToken(JwtUtil.getTokenStringFromRequest(HttpRequestUtil.getRequest()));
		if (loginToken.getUserId().equals(userId)) {
			throw new CustomException("不能清空当前登录账号的数据，请使用其他账号执行操作");
		}
		// 最高管理员不能被删除
		List<SysRole> roleList = roleService.getRolesByUserId(userId);
		if (roleList.stream().anyMatch(role -> SpecialRoleEnum.MASTER.getRoleCode().equals(role.getRoleCode()))) {
			throw new CustomException(SpecialRoleEnum.MASTER.getRoleName() + "不能被删除");
		}
		// 删除用户
		removeById(userId);
		// 删除用户和角色的关联关系
		userRoleService.lambdaUpdate().eq(SysUserRole::getUserId, userId).remove();
		// 删除产线收藏
		userProductionService.lambdaUpdate().eq(GUserProduction::getUserId, userId).remove();
		// 删除话题
		List<Long> topicIdList = topicService.lambdaQuery().eq(SysTopic::getUserId, userId).select(SysTopic::getId).list().stream().map(BasePo::getId).collect(Collectors.toList());
		if (!topicIdList.isEmpty()) {
			// 删除话题
			topicService.lambdaUpdate().in(SysTopic::getId, topicIdList).remove();
			// 删除话题点赞
			topicLikeService.lambdaUpdate().in(SysTopicLike::getTopicId, topicIdList).remove();
			List<Long> commonIdList = commentService.lambdaQuery().in(SysTopicComment::getTopicId, topicIdList).select(SysTopicComment::getId).list().stream().map(BasePo::getId).collect(Collectors.toList());
			if (!commonIdList.isEmpty()) {
				// 删除话题下的所有评论
				commentService.lambdaUpdate().in(SysTopicComment::getId, commonIdList).remove();
				// 删除评论点赞
				commentLikeService.lambdaUpdate().in(SysTopicCommentLike::getTopicCommentId, commonIdList).remove();
			}
		}
		// 删除评论
		commentService.lambdaUpdate().eq(SysTopicComment::getUserId, userId).remove();
		// 删除点赞
		topicLikeService.lambdaUpdate().eq(SysTopicLike::getUserId, userId).remove();
		commentLikeService.lambdaUpdate().eq(SysTopicCommentLike::getUserId, userId).remove();
		// 删除用户的网站设置
		webConfigService.lambdaUpdate().eq(SysWebConfig::getUserId, userId).remove();
		// 删除用户的操作日志
		logService.lambdaUpdate().eq(SysLog::getOperator, user.getUsername()).remove();
		// 更新缓存
		redissonCacheService.cacheSysUser(list()).throwExceptionIfFailed();
		redissonCacheService.cacheSysUserRole(userRoleService.getAllSysUserRole()).throwExceptionIfFailed();
		return Result.success();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Result<SysUser> modifyEmailNotifyTypes(ModifyEmailNotifyTypesRequest request) {
		SysUser user = getById(request.getUserId());
		if (user == null) {
			throw new CustomException("用户不存在");
		}
		user.setEmailNotifyTypes(request.getEmailNotifyTypes()).updateById();
		return Result.successWithData(user);
	}

	@Override
	public List<SysUser> getUsersByRoleId(Long roleId) {
		return mapper.getUsersByRoleId(roleId);
	}

	@Override
	public List<SysUser> getUsersByRoleCode(String roleCode) {
		SysRole role = roleService.lambdaQuery().eq(SysRole::getRoleCode, roleCode).one();
		return getUsersByRoleId(role.getId());
	}

}
